Next | Prev | Up | Top | Contents | Index

Using the udmalib Functions

All DMA engine transfers are initiated by a special device driver. However, you do not access this driver through open/read/write system functions. Instead, you program it through a library of functions. The functions are documented in the udmalib(3) reference page. They are used in the following sequence:

  1. Call dma_open() to initialize action to a particular VME card.

  2. Call dma_allocbuf() to allocate storage to use for DMA buffers.

  3. Call dma_mkparms() to create a descriptor for an operation, including the buffer, the length, and the direction of transfer.

  4. Call dma_start() to execute each transfer. This function does not return until the transfer is complete.
The dma_start() function takes the VME bus address of the particular slave device register that will provide or accept a series of data items. Before starting a DMA transfer, and possibly between transfers, you may need to program the VME controller with other commands. You would do this using PIO (see "VME Programmed I/O").

Tip: The dma_start() function operates synchronously, polling the VME adapter hardware to find out when the DMA transfer is complete. In order to get parallel execution, consider calling dma_start() from a separate process.


Buffer Allocation for User DMA

A buffer allocated by dma_allocbuf() is rounded up to a multiple of the memory page size, and is locked in memory to avoid page-faults during the DMA transfer. There is some overhead in creating a buffer, so for best performance the program should allocate the required buffers of the necessary size during initialization. However, if the total size of the buffers is a significant fraction of the available real memory, the large number of locked pages can hurt system performance.

You can only use the allocated buffer for DMA; it is not possible to provide your own buffer (for example, a buffer in a shared memory arena) for use by the DMA engine. When the data is produced by one process and written by another, this design can mean that the data has to be copied from an application buffer to the DMA buffer.

Tip: One way to avoid copying is to call dma_allocbuf() early, during program setup, before creating subprocesses using sproc(). Processes made with sproc() share their parent process address space, including buffer space created by dma_allocbuf(), so you can have a process generating or consuming data in one part of the allocated buffer space while a different process executes dma_start() to write or read data in a different part. It is of course essential to synchronize the use of the different buffer segments so that each area is used by only one process at a time.


Allocation of Descriptors

Each call to dma_mkparms() allocates a small block of memory and fills it with constants that describe a particular transfer operation. The primary input to dma_mkparms() is a vme_parms_t object (declared in udmalib.h) containing the following important fields:

vp_block 1 for a block-mode transfer; 0 for a normal transfer.
vp_datumsz The width of transfer units: VME_DS_BYTE 8-bit transfers)
VME_DS_HALFWORD (16-bit transfers) VME_DS_WORD (32-bit transfers), or VME_DS_DBLWORD (64-bit transfers).
vp_dir The direction of transfer: either VME_READ (from the VME bus) or VME_WRITE (to the VME bus).
vp_throt For a block-mode transfer, the number of bytes to transfer in one burst without yielding the bus. Set to either VME_THROT_256 (the usual size, supported by most VME slaves that allow block transfer) or VME_THROT_2048 to allow up to 2,048 bytes per burst.
vp_release The bus arbitration mode: VME_REL_RWD to release the bus as soon as the transfer is over, or VME_REL_ROR to release only when another bus master wants the bus. Use VME_REL_ROR for best speed when no bus masters are on the bus. Use VME_REL_RWD when other bus masters may be present and active.
vp_addrmod The address modifier value that selects the target VME address space. Names of the form VME_*AMOD are declared for these values in sys/vmereg.h, for example VME_A16NPAMOD for the nonpriviliged A16 space.

During initialization you call dma_mkparms() to create a descriptor for each unique combination of parameters that your program will use. In each call to dma_start(), you pass the descriptor that contains the appropriate set of parameters. A descriptor can be used in multiple dma_start() calls.


Next | Prev | Up | Top | Contents | Index